'use client';

import type { TMetadata } from '@/types';
import type {
  IPagination,
  IPost,
  IQueryParams,
  ISectionClient,
  ISectionDetails,
  ISectionGroup,
  ITag,
} from '@/interfaces';
import useUser from '@/hooks/useUser';
import { useEffect, useState } from 'react';
import { useInfiniteQuery, useQuery } from '@tanstack/react-query';
import {
  clientQueryAllPost,
  clientQueryAllSection,
  clientQuerySectionDetailsById,
  queryPostRandom,
} from '@/services/api';
import {
  getSectionQueryParams,
  getTagQueryParams,
  toRelativeTime,
} from '@/lib/tool';
import LoadPage from '@/app/[locale]/load/load';
import ErrorPage from '@/app/[locale]/error/error';
import useToast from '@/hooks/useToast';
import { NavbarPage } from '@/app/[locale]/navbar';
import FooterPage from '@/app/[locale]/footer';
import { useSearchParams } from 'next/navigation';
import PostHome from '@/app/[locale]/home/post';
import { HomePageContext } from '@/contexts/home';
import type { ReadonlyURLSearchParams } from 'next/dist/client/components/navigation';
import LeftHome from '@/app/[locale]/home/left';
import RightHome from '@/app/[locale]/home/right';
import Nodata from '@/app/[locale]/common/nodata/nodata';
import { useTranslations } from 'use-intl';

export default function HomePage({ metadata }: { metadata: TMetadata }) {
  return (
    <>
      <NavbarPage metadata={metadata} />
      <Home metadata={metadata} />
      <FooterPage metadata={metadata} />
    </>
  );
}

const Home = ({ metadata }: { metadata: TMetadata }) => {
  const searchParams = useSearchParams();
  const [currentTagItem, setCurrentTagItem] = useState<ITag | undefined>(
    getTagQueryParams(searchParams),
  );
  const [currentSectionItem, setCurrentSectionItem] = useState<
    ISectionClient | undefined
  >(getSectionQueryParams(searchParams));
  const [currentSectionGroupItem, setCurrentSectionGroupItem] = useState<
    ISectionGroup | undefined
  >(getSectionGroupQueryParams(searchParams));
  const [sectionPostParams, setSectionPostParams] = useState<IQueryParams>({});
  const [allPostParams, setAllPostParams] = useState<IQueryParams>({});
  const userQuery = useUser(metadata);
  const { show } = useToast();
  const [pages, setPages] = useState<IPost[]>(
    currentSectionItem
      ? (metadata.all['postsBySectionId']?.v as ISectionDetails)?.data
          ?.content ?? []
      : (metadata.all['posts'].v as IPagination<IPost>).content,
  );
  const t = useTranslations('HomePage');

  const clientQueryAllSectionQuery = useQuery(
    metadata.all['sections'].k,
    async () => {
      return (await clientQueryAllSection()) as ISectionClient[];
    },
    {
      initialData: metadata.all['sections'].v as ISectionClient[],
    },
  );
  const queryPostRandomQuery = useQuery(
    metadata.all['randomPost'].k,
    async () => {
      return (await queryPostRandom()) as IPost[];
    },
    {
      initialData: metadata.all['randomPost'].v as IPost[],
    },
  );
  const clientQuerySectionDetailsByIdQuery = useInfiniteQuery(
    [
      '/forum',
      '/sections',
      '/client',
      currentSectionItem?.id,
      '/details',
      sectionPostParams,
      'infinite',
    ],
    async (context) => {
      return (await clientQuerySectionDetailsById({
        id: context.queryKey[3],
        query: {
          ...(context.queryKey[5] as IQueryParams),
          ...context.pageParam,
        },
      })) as ISectionDetails;
    },
    {
      enabled: !!currentSectionItem,
      keepPreviousData: true,
      getPreviousPageParam: (firstPage) => {
        if (firstPage.data && firstPage.data.pageable.previous) {
          return {
            page: Math.max(firstPage.data.pageable.page - 1, 0),
          };
        }
      },
      getNextPageParam: (lastPage) => {
        if (lastPage.data && lastPage.data.pageable.next) {
          return {
            page: Math.min(
              lastPage.data.pageable.page + 1,
              lastPage.data.pageable.pages,
            ),
          };
        }
      },
      initialData: () => {
        if (metadata.all['postsBySectionId']) {
          return {
            pages: [metadata.all['postsBySectionId'].v as ISectionDetails],
            pageParams: [
              {
                page: Math.max(
                  ((metadata.all['postsBySectionId'].k[5] as IQueryParams)
                    .page ?? 1) - 1,
                  0,
                ),
              },
            ],
          };
        }
      },
    },
  );
  const clientQueryAllPostQuery = useInfiniteQuery(
    ['/forum', '/posts', '/client', allPostParams],
    async (context) => {
      return (await clientQueryAllPost({
        query: {
          ...(context.queryKey[3] as IQueryParams),
          ...context.pageParam,
        },
      })) as IPagination<IPost>;
    },
    {
      enabled: !currentSectionItem,
      keepPreviousData: true,
      getPreviousPageParam: (firstPage) => {
        if (firstPage.pageable.previous) {
          return {
            page: Math.max(firstPage.pageable.page - 1, 0),
          };
        }
      },
      getNextPageParam: (lastPage) => {
        if (lastPage.pageable.next) {
          return {
            page: Math.min(lastPage.pageable.page + 1, lastPage.pageable.pages),
          };
        }
      },
      initialData: () => {
        if (metadata.all['posts']) {
          return {
            pages: [metadata.all['posts'].v as IPagination<IPost>],
            pageParams: [
              {
                page: Math.max(
                  ((metadata.all['posts'].k[3] as IQueryParams).page ?? 1) - 1,
                  0,
                ),
              },
            ],
          };
        }
      },
    },
  );

  useEffect(() => {
    if (currentSectionItem) {
      if (clientQuerySectionDetailsByIdQuery.data) {
        setPages(
          clientQuerySectionDetailsByIdQuery.data.pages
            .flatMap((item) => item.data?.content ?? [])
            .map((item) => {
              item._contentUpdatedOnText = toRelativeTime(
                item.contentUpdatedOn,
              );
              return item;
            }),
        );
      }
    } else {
      if (clientQueryAllPostQuery.data) {
        setPages(
          clientQueryAllPostQuery.data.pages
            .flatMap((item) => item.content)
            .map((item) => {
              item._contentUpdatedOnText = toRelativeTime(
                item.contentUpdatedOn,
              );
              return item;
            }),
        );
      }
    }
  }, [
    clientQueryAllPostQuery.data,
    clientQuerySectionDetailsByIdQuery.data,
    currentSectionItem,
  ]);

  function getSectionGroupQueryParams(searchParams: ReadonlyURLSearchParams) {
    const sectionId = getSectionQueryParams(searchParams)?.id;
    if (sectionId) {
      const find = (metadata.all['sections'].v as ISectionClient[]).find(
        (item) => item.id === sectionId,
      );
      return find?.sectionGroup;
    }
  }

  async function onClickLoadMore() {
    try {
      if (currentSectionItem) {
        await clientQuerySectionDetailsByIdQuery.fetchNextPage();
      } else {
        await clientQueryAllPostQuery.fetchNextPage();
      }
    } catch (e) {
      show({
        type: 'DANGER',
        message: e,
      });
    }
  }

  async function onClickRefresh() {
    try {
      await queryPostRandomQuery.refetch({ throwOnError: true });

      show({
        type: 'PRIMARY',
        message: t('changeBatchComplete'),
      });
    } catch (e) {
      show({
        type: 'DANGER',
        message: e,
      });
    }
  }

  if (
    userQuery.data &&
    clientQueryAllSectionQuery.data &&
    queryPostRandomQuery.data &&
    clientQueryAllPostQuery.data
  ) {
    return (
      <HomePageContext.Provider
        value={{
          metadata,
          currentSectionGroupItem,
          setCurrentSectionGroupItem,
          currentSectionItem,
          setCurrentSectionItem,
          currentTagItem,
          setCurrentTagItem,
        }}
      >
        <LeftHome sections={clientQueryAllSectionQuery.data} />
        <div className="col mt-4 overflow-hidden">
          <div className="vstack gap-4 mx-4">
            <PostHome items={pages} />

            <Loading
              isInitialLoading={
                clientQueryAllPostQuery.isInitialLoading ||
                clientQuerySectionDetailsByIdQuery.isInitialLoading
              }
            />

            {pages.length === 0 ? (
              <Nodata />
            ) : (
              <LoadMoreBtn
                isDisabled={
                  currentSectionItem
                    ? !clientQuerySectionDetailsByIdQuery.hasNextPage ||
                      clientQuerySectionDetailsByIdQuery.isFetchingNextPage
                    : !clientQueryAllPostQuery.hasNextPage ||
                      clientQueryAllPostQuery.isFetchingNextPage
                }
                isFetchingNextPage={
                  currentSectionItem
                    ? clientQuerySectionDetailsByIdQuery.isFetchingNextPage
                    : clientQueryAllPostQuery.isFetchingNextPage
                }
                onClickLoadMore={onClickLoadMore}
              />
            )}

            <div></div>
          </div>
        </div>
        <RightHome
          isLoading={queryPostRandomQuery.isLoading}
          onClickRefresh={onClickRefresh}
          items={queryPostRandomQuery.data}
          data={userQuery.data}
        />
      </HomePageContext.Provider>
    );
  }

  if (
    userQuery.error ||
    clientQueryAllSectionQuery.error ||
    queryPostRandomQuery.error ||
    clientQuerySectionDetailsByIdQuery.error ||
    clientQueryAllPostQuery.error
  ) {
    return (
      <ErrorPage
        error={
          userQuery.error ||
          clientQueryAllSectionQuery.error ||
          queryPostRandomQuery.error ||
          clientQuerySectionDetailsByIdQuery.error ||
          clientQueryAllPostQuery.error
        }
      />
    );
  }

  return <LoadPage />;
};

const Loading = ({ isInitialLoading }: { isInitialLoading?: boolean }) => {
  const t = useTranslations('HomePage');

  return (
    <>
      {isInitialLoading && (
        <div className="row">
          <div className="col bg-white rounded p-4">
            <div className="vstack gap-4 py-4">
              <div className="vstack gap-3 align-items-center mt-4 text-secondary user-select-none">
                <div className="spinner-border" role="status">
                  <span className="visually-hidden">Loading...</span>
                </div>
                <div>{t('loading')}...</div>
              </div>
            </div>
          </div>
        </div>
      )}
    </>
  );
};

const LoadMoreBtn = ({
  onClickLoadMore,
  isDisabled,
  isFetchingNextPage,
}: {
  onClickLoadMore: () => void;
  isDisabled: boolean;
  isFetchingNextPage: boolean;
}) => {
  return (
    <div className="row mt-4 mb-3">
      <div className="col">
        <button
          onClick={onClickLoadMore}
          disabled={isFetchingNextPage && isDisabled}
          type="button"
          className="btn rounded-pill text-secondary-emphasis w-100"
        >
          {isFetchingNextPage ? (
            <>
              <span
                className="spinner-border spinner-border-sm me-2"
                role="status"
                aria-hidden="true"
              ></span>
              Loading...
            </>
          ) : (
            <i className="bi bi-three-dots"></i>
          )}
        </button>
      </div>
    </div>
  );
};
